package net.towee.client.widgets.upload.impl;

import net.towee.client.widgets.upload.UploadError;
import net.towee.client.widgets.upload.UploadEvent;
import net.towee.client.widgets.upload.UploadForm;
import net.towee.client.widgets.upload.UploadHandler;
import net.towee.client.widgets.upload.UploadItem;
import net.towee.client.widgets.upload.UploadStartHandler;

import com.google.common.base.Preconditions;
import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ChangeEvent;
import com.google.gwt.event.dom.client.ChangeHandler;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.FileUpload;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.FormPanel;
import com.google.gwt.user.client.ui.FormPanel.SubmitCompleteEvent;
import com.google.gwt.user.client.ui.FormPanel.SubmitCompleteHandler;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.Widget;

public class UploadFormBasic extends AbstractUploadForm implements UploadForm, ChangeHandler {

	private class UploadItemImpl extends AbstractUploadItem implements SubmitCompleteHandler {
		private final FileUpload upl;
		private final FormPanel form;

		public UploadItemImpl(FileUpload upl) {
			this.upl  = upl;
			this.form = (FormPanel)upl.getParent(); 
			this.fileName = upl.getFilename().substring(upl.getFilename().lastIndexOf("\\")+1);
			
			form.addSubmitCompleteHandler(this);
			form.setVisible(false);
		}

		@Override
		public void start() {
			Preconditions.checkNotNull(handler, "you must set handler first");
			
			if(uploadingPoolSize == MAX_CONCURENT_UPLOADING) {
				handler.onUploadItemQueued();
				uploadQueue.add(this);
				state = UploadState.QUEUED;
			}
			else {
				uploadingPoolSize++;
				state = UploadState.STARTED;
				handler.onUploadingStarted(false);
				form.submit();
			}
		}

		@Override
		public void cancel() {
			state = UploadState.CANCELED;
			form.reset();
			form.removeFromParent();
			uploadItems.remove(this);
			handler.onCancelUploading();
			freeQueue();
		}

		@Override
		public void onSubmitComplete(SubmitCompleteEvent event) {
			HTML stripHTML = new HTML();
			stripHTML.setHTML(event.getResults());
			
			if(stripHTML.getText().length() <= 2) {
				state = UploadState.ERROR;
				handler.onErrorUploading( UploadError.fromString(stripHTML.getText()) );
			}
			else {
				state = UploadState.COMPLITED;
				handler.onCompleteUploading( stripHTML.getText().trim() );
				UploadFormBasic.this.fireEvent( new UploadEvent(stripHTML.getText().trim()) );
			}
			
			freeQueue();
		}
		
	}
	
	private FileUpload uploadInput;
	private FlowPanel uploadFromsContainer = new FlowPanel();
	
	public UploadFormBasic() {
		add(uploadFromsContainer);
	    addForm();
	}
	
	private void addForm() {
	    FormPanel form = new FormPanel();
	    
	    uploadInput = new FileUpload();
	    form.setEncoding(FormPanel.ENCODING_MULTIPART);
        form.setMethod(FormPanel.METHOD_POST);
        form.add(uploadInput);
        
        uploadInput.setName("file");
        uploadInput.addChangeHandler(this);
        uploadFromsContainer.add(form);
	}

	@Override
	public void onChange(ChangeEvent event) {
		if(uploadItems.size() == filesLimit) {
			for(UploadStartHandler h : handlers) 
				h.onOutOfLimit();
		}	else {
			// Get the form
			FileUpload upl = (FileUpload)event.getSource();
			FormPanel form = (FormPanel)upl.getParent();
			form.setAction(GWT.getHostPageBaseURL()+"attachment");
        
			// Create file item
			UploadItem item = new UploadItemImpl(upl);
		
			// Add new form
			addForm();
			
			for(UploadStartHandler h : handlers) {
				uploadItems.add(item);
				h.onUploadingStarted(item);
			}
		}
	}

	@Override
	public boolean isDropSupported() {
		return false;
	}

	@Override
	public HandlerRegistration addUploadHandler(UploadHandler handler) {
		return addHandler(handler, UploadEvent.getType());
	}

	@Override
	public Widget getUploadInputWidget() {
		return uploadFromsContainer;
	}
}
